package com.shell.customer.trade.service.impl;

import com.shell.bee.acct.AcctBlcService;
import com.shell.bee.acct.AcctService;
import com.shell.bee.acct.account.po.AcctBas;
import com.shell.bee.acct.account.po.AcctBkp;
import com.shell.bee.acct.account.po.AcctCard;
import com.shell.bee.acct.transaction.vo.AcctInfo;
import com.shell.bee.base.exception.UnCheckException;
import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.base.utils.SpringContextUtil;
import com.shell.bee.base.utils.StringUtil;
import com.shell.bee.base.utils.SystemUtil;
import com.shell.constant.rel.AssetCode;
import com.shell.customer.base.dao.CusRecDao;
import com.shell.customer.chain.service.ChainAcctService;
import com.shell.customer.chain.vo.ChainAcct;
import com.shell.customer.po.CusAcct;
import com.shell.customer.po.CusRec;
import com.shell.customer.trade.service.CustomerAcctService;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service("customerAcctService")
public class CustomerAcctServiceImpl implements CustomerAcctService {
	@Autowired
	private AcctService acctService;
	@Autowired
	private CusRecDao cusRecDao;
	@Autowired
	private ChainAcctService chainAcctService;
	@Autowired
	private AcctBlcService acctBlcService;
	@Value("${chain.switch: off}")
	private String chainSwitch;

	private AcctBas getAcctForOpen(String fiNo, CusRec cust, String acctUse, String oaaChnCode, String acctType) {
		AcctBas base = this.acctService.getAcctBas(cust.getCusId(), acctType, acctUse);
		if (base == null) {
			base = genBaseInfo(fiNo, cust, acctUse, oaaChnCode, acctType);
		} else {
			base = null;
		}
		return base;
	}

	private AcctBas genBaseInfo(String fiNo, CusRec cust, String acctUse, String oaaChnCode, String acctType) {
		AcctBas base = new AcctBas();

		base.setCustId(cust.getCusId());
		base.setCustNm(cust.getCusName());
		base.setAcctType(acctType);
		base.setAcctNm(cust.getCusName());

		base.setCustAcctType("C");
		base.setOaaChnCode(oaaChnCode);
		base.setOaaDt(DateUtil.getSystemDate());
		base.setAcctSts(String.valueOf("N"));
		base.setFiNo(fiNo);
		if (StringUtil.notTrimEmpty(fiNo)) {
			CusRec cus = (CusRec) this.cusRecDao.selectByPrimaryKey(fiNo);
			if (cus != null) {
				base.setFiNm(cus.getCusName());
			}
		}
		base.setDataScLvl("B");
		base.setUseCode(acctUse);
		return base;
	}

	private AcctBas getAcctForAdd(String cusNm, CusAcct acct) {
		AcctBas base = new AcctBas();
		base.setAcctNo(acct.getAcctNo());
		base.setCustId(acct.getCusId());
		base.setCustNm(cusNm);
		if (StringUtil.emptyAndNull(acct.getAcctType())) {
			base.setAcctType("0");
		} else {
			base.setAcctType(acct.getAcctType());
		}
		base.setAcctNm(acct.getAcctName());
		base.setAcctAlias(acct.getAcctName());

		base.setFiNo(acct.getBankCode());

		StringBuilder builder = new StringBuilder();
		appendNotNull(builder, acct.getBankProvince());
		appendNotNull(builder, acct.getBankCity());
		appendNotNull(builder, acct.getBankName());
		appendNotNull(builder, acct.getBankDot());
		base.setFiNm(builder.toString());

		base.setCustAcctType("C");
		base.setOaaChnCode("B");
		base.setOaaDt(DateUtil.getSystemDate());
		base.setAcctSts(String.valueOf(acct.getAcctState()));
		base.setDataScLvl("B");
		return base;
	}

	private void appendNotNull(StringBuilder builder, String str) {
		if (!StringUtil.emptyAndNull(str)) {
			builder.append(str);
		}
	}

	private String[] getAcctTypes(String cusType) {
		String[] acctTypes = null;
		switch (cusType) {
		case "FINNER":
			acctTypes = new String[] { "1", "2" };
			break;
		default:
			acctTypes = new String[] { "1" };
		}
		return acctTypes;
	}

	public void addAcct(CusAcct acct, CusRec cusRec, String[] uses) {
		AcctBas trdAcct = getAcctForAdd(cusRec.getCusName(), acct);

		List<String> useCodes = new ArrayList();
		Set<String> useCodeSet = new HashSet();
		if ((uses != null) && (uses.length > 0)) {
			useCodeSet.addAll(Arrays.asList(uses));
		}
		useCodes.addAll(useCodeSet);
		trdAcct.setUseCodes(useCodes);
		this.acctService.add(trdAcct);
	}

	public List<AcctBas> openAcct(String fiNo, CusRec cusRec, String[] acctTypes) {
		List<AcctBas> accts = new ArrayList();
		AcctBas bas = null;
		if (acctTypes != null) {
			for (String acctType : acctTypes) {
				bas = getAcctForOpen(fiNo, cusRec, null, "C", acctType);
				if (bas != null) {
					accts.add(bas);
				}
			}
		}
		Set<String> set;
		int counter;
		AcctBas base;
		if (accts.size() > 0) {
			String[] realAcctTypes = new String[accts.size()];
			for (int i = 0; i < accts.size(); i++) {
				realAcctTypes[i] = ((AcctBas) accts.get(i)).getAcctType();
			}
			Object list = getAssetCodeListByAcctTypes(realAcctTypes);
			Object chainAccts = new ArrayList();
			if ("on".equals(this.chainSwitch)) {
				try {
					ChainAcct chainAcct = null;
					for (Iterator localIterator = ((List) list).iterator(); localIterator.hasNext();) {
						set = (Set) localIterator.next();
						chainAcct = this.chainAcctService.open(set);
						((List) chainAccts).add(chainAcct);
					}
				} catch (Exception e) {
					throw new UnCheckException("������������������", e);
				}
			} else {
				for (int i = 0; i < realAcctTypes.length; i++) {
					((List) chainAccts).add(new ChainAcct(SystemUtil.getUUID(), null));
				}
			}
			counter = 0;
			base = null;
			for (ChainAcct chainAcct : (List<ChainAcct>) chainAccts) {
				base = (AcctBas) accts.get(counter);
				base.setAcctNo(chainAcct.getPublicKey());
				base.setAcctKey(chainAcct.getPrivateKey());
				base.setInitBkp(false);
				if ("FINNER".equals(cusRec.getCusType())) {
					initAcctBkp(base.getAcctNo(), AssetCode.XQT.name(), cusRec.getGrpId(), cusRec.getFinId(),
							BigDecimal.ZERO);
					initAcctBkp(base.getAcctNo(), AssetCode.XCB.name(), cusRec.getGrpId(), cusRec.getFinId(),
							BigDecimal.ZERO);
				} else {
					initAcctBkp(base.getAcctNo(), AssetCode.XCB.name(), cusRec.getGrpId(), null, BigDecimal.ZERO);
				}
				counter++;
				this.acctService.add(base);
			}
		}
		return accts;
	}

	public List<AcctBas> openChainVitualAcct(String fiNo, CusRec cusRec) {
		String[] acctTypes = getAcctTypes(cusRec.getCusType());
		return openAcct(fiNo, cusRec, acctTypes);
	}

	private List<Set<String>> getAssetCodeListByAcctTypes(String[] acctTypes) {
		List<Set<String>> list = new ArrayList();
		Set<String> assetCodeSet = null;
		for (int i = 0; i < acctTypes.length; i++) {
			assetCodeSet = new HashSet();
			assetCodeSet.add(AssetCode.XCB.name());
			assetCodeSet.add(AssetCode.XQT.name());
			list.add(assetCodeSet);
		}
		return list;
	}

	public AcctBas openPlatVitualAcct(CusAcct acct, CusRec cusRec, String[] uses) {
		AcctBas tmp = null;
		if (uses != null) {
			for (String acctUse : uses) {
				tmp = getAcctForOpen(null, cusRec, acctUse, "P", "1");
				if (tmp != null) {
					break;
				}
			}
			if (tmp == null) {
				return null;
			}
		}
		AcctBas acctBas = getPlatVirtualAcctForOpen(cusRec, "P", "1");
		if (acctBas == null) {
			acctBas = tmp;
			acctBas.setFiNm(acct.getBankName());
		}
		if (StringUtil.empty(acctBas.getAcctNo())) {
			acctBas.setAcctNo(SystemUtil.getUUID());
		}
		if ((uses != null) && (uses.length > 0)) {
			acctBas.setUseCodes(Arrays.asList(uses));
		}
		this.acctService.add(acctBas);
		return acctBas;
	}

	private AcctBas getPlatVirtualAcctForOpen(CusRec cusRec, String oaaChnCode, String acctType) {
		AcctBas acctBas = new AcctBas();
		acctBas.setCustId(cusRec.getCusId());
		acctBas.setAcctType(acctType);
		List<AcctBas> bass = this.acctService.getAcctBasList(acctBas);
		AcctBas base = null;
		if ((bass == null) || (bass.size() == 0)) {
			base = genBaseInfo(null, cusRec, null, oaaChnCode, acctType);
		} else {
			base = (AcctBas) bass.get(0);
		}
		return base;
	}

	public AcctCard openBankVirtualAcct(String bankCode, CusRec cus, String acctNo) {
		String virtualAcctUseStr = SpringContextUtil.getProperty("virtual.acct.use");
		String[] virtualAcctUses = StringUtil.emptyAndNull(virtualAcctUseStr) ? null : virtualAcctUseStr.split(",");
		List<String> virtualUseCodes = virtualAcctUses == null ? null : Arrays.asList(virtualAcctUses);

		AcctCard platformAcct = getPlatSpclAcct(bankCode);
		if (platformAcct == null) {
			throw new UnCheckMsgException("��������������������������������");
		}
		return addBankVirtualAcct(platformAcct, cus, virtualUseCodes, acctNo);
	}

	public int delAcctCard(CusAcct acct) {
		AcctCard card = new AcctCard();
		card.setAcctNo(acct.getAcctNo());
		card.setAcctSts("C");
		return this.acctService.updateCard(card);
	}

	public void addCard(CusAcct acct, CusRec cusRec, String[] uses) {
		AcctCard card = getCardForAdd(cusRec.getCusName(), acct);

		List<String> useCodes = new ArrayList();
		Set<String> useCodeSet = new HashSet();
		if ((uses != null) && (uses.length > 0)) {
			useCodeSet.addAll(Arrays.asList(uses));
		}
		useCodes.addAll(useCodeSet);
		card.setUseCodes(useCodes);
		card.setCurrCode(AssetCode.CNY.name());
		this.acctService.addCard(card);
	}

	public void initAcctBkp(String acctNo, String currCode, String grpId, String finId, BigDecimal acctAmt) {
		AcctBkp acctBkp = new AcctBkp();
		acctBkp.setAcctNo(acctNo);
		acctBkp.setPrdAccFncCls("PC");
		acctBkp.setCurrCode(currCode);
		acctBkp.setBkpPrdCode(grpId);
		acctBkp.setBkpCttNo(finId);
		acctBkp.setAcctAmt(acctAmt);
		this.acctBlcService.add(acctBkp);
	}

	public List<AcctInfo> getAcctInfos(AcctInfo acct) {
		return this.acctService.getAcctInfos(acct);
	}

	public AcctBkp getAcctBkp(String bkpId) {
		return this.acctBlcService.selectAcctBkpById(bkpId);
	}

	public void moveHistory(AcctBkp acctBkp) {
		this.acctBlcService.moveHistory(acctBkp);
	}

	public AcctBas getAcctBas(String acctNo) {
		return this.acctService.getAcctBas(acctNo);
	}

	public AcctBas getAcctBas(String cusId, String acctType, String acctUse) {
		return this.acctService.getAcctBas(cusId, acctType, acctUse);
	}

	public AcctBkp getAcctBkp(String acctNo, String currCode) {
		return this.acctBlcService.getAcctBkp(acctNo, currCode, null);
	}

	public AcctCard getCard(AcctCard card) {
		return this.acctService.getAcctCard(card);
	}

	public List<AcctInfo> getAcctCardInfos(AcctInfo acctInfo) {
		return this.acctService.getAcctCardInfos(acctInfo);
	}

	public void delAcctUse(String custId, String acctType, String acctUse) {
		this.acctService.delAcctUse(custId, acctType, acctUse);
	}

	private AcctCard getCardForAdd(String cusNm, CusAcct acct) {
		AcctCard base = new AcctCard();
		base.setAcctNo(acct.getAcctNo());
		base.setCustId(acct.getCusId());
		base.setCustNm(cusNm);
		if (StringUtil.emptyAndNull(acct.getAcctType())) {
			base.setAcctType("0");
		} else {
			base.setAcctType(acct.getAcctType());
		}
		base.setAcctNm(acct.getAcctName());
		base.setAcctAlias(acct.getAcctName());

		base.setHqFiNo(acct.getBankCode());
		base.setHqFiNm(acct.getBankName());
		base.setFiNo(acct.getBankCode());
		base.setFiNm(acct.getBankDot());
		base.setFiPrvnNm(acct.getBankProvince());
		base.setFiCityNm(acct.getBankCity());

		base.setCustAcctType("C");
		base.setOaaChnCode("B");
		base.setOaaDt(DateUtil.getSystemDate());
		base.setAcctSts(String.valueOf(acct.getAcctState()));
		base.setDataScLvl("B");
		return base;
	}

	private AcctCard addBankVirtualAcct(AcctCard platformAcct, CusRec cus, List<String> useCodes, String acctNo) {
		AcctCard tmp = new AcctCard();
		tmp.setCustId(cus.getCusId());
		tmp.setFiNo(platformAcct.getFiNo());
		tmp.setAcctType("1");
		tmp.setAcctSts("N");
		tmp.setOaaChnCode("B");
		AcctCard card = this.acctService.getAcctCard(tmp);
		if (card == null) {
			card = new AcctCard();
			card.setAcctType("1");
			card.setOaaChnCode("B");
			card.setCustAcctType("C");
			card.setCurrCode(AssetCode.CNY.name());
			card.setAcctNo(platformAcct.getAcctNo() + acctNo);
			card.setAcctNm(cus.getCusName());
			card.setHqFiNo(platformAcct.getHqFiNo());
			card.setHqFiNm(platformAcct.getHqFiNm());
			card.setFiNo(platformAcct.getFiNo());
			card.setFiNm(platformAcct.getFiNm());
			card.setFiPrvnNm(platformAcct.getFiPrvnNm());
			card.setFiCityNm(platformAcct.getFiCityNm());

			card.setCustId(cus.getCusId());
			card.setCustNm(cus.getCusName());
			card.setUseCodes(useCodes);
			card.setInitBkp(false);
			this.acctService.addCard(card);
			return card;
		}
		return null;
	}

	private AcctCard getPlatSpclAcct(String bankCode) {
		AcctCard card = new AcctCard();
		card.setCustId("platform");
		card.setFiNo(bankCode);
		card.setAcctType("1");
		card.setOaaChnCode("B");
		return this.acctService.getAcctCard(card);
	}
}
